const { UUID_TYPE, CHARS } = require('@/constant');
/**
 * 生成一个uuid
 * @param {Number} type 选择方法类型 传值为 UUID_TYPE: { NORMAL: 1, FAST: 2, COMPACT: 3 }
 * @returns {Function} 返回一个方法 注意：type为NORMAL时可以传值{ len = 32, radix = 16 }
 */
module.exports = function UUID(type = UUID_TYPE.FAST) {
  const map = {
    [UUID_TYPE.NORMAL]: function ({ len, radix } = { len: 32, radix: 16 }) {
      const chars = CHARS;
      let uuid = [];

      if (len) {
        // Compact form
        for (let i = 0; i < len; i++)
          uuid[i] =
            chars[
              0 | (Math.random() * (radix > chars.length ? chars.length : radix || chars.length))
            ];
      } else {
        // rfc4122, version 4 form
        let r = null;

        // rfc4122 requires these characters
        uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
        uuid[14] = '4';

        // Fill in random data.  At i==19 set the high bits of clock sequence as
        // per rfc4122, sec. 4.1.5
        for (let i = 0; i < 36; i++) {
          if (!uuid[i]) {
            r = 0 | (Math.random() * 16);
            uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
          }
        }
      }

      return uuid.join('');
    },
    [UUID_TYPE.FAST]: function () {
      const chars = CHARS;
      let uuid = new Array(36),
        rnd = 0,
        r;
      for (let i = 0; i < 36; i++) {
        if (i == 8 || i == 13 || i == 18 || i == 23) {
          uuid[i] = '-';
        } else if (i == 14) {
          uuid[i] = '4';
        } else {
          if (rnd <= 0x02) rnd = (0x2000000 + Math.random() * 0x1000000) | 0;
          r = rnd & 0xf;
          rnd = rnd >> 4;
          uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
        }
      }
      return uuid.join('');
    },
    [UUID_TYPE.COMPACT]: function () {
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        const r = (Math.random() * 16) | 0,
          v = c === 'x' ? r : (r & 0x3) | 0x8;
        return v.toString(16);
      });
    }
  };
  return (
    map[type] ||
    (() => {
      throw new Error(`The UUID argument 'type' is not a correct option`);
    })
  );
};
